package net.sk.china.platform.service.impl.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import net.sk.china.common.exception.TalkException;
import net.sk.china.common.model.order.StoreOrder;
import net.sk.china.common.model.order.StoreOrderInfo;
import net.sk.china.common.model.order.StoreOrderStatus;
import net.sk.china.common.model.product.StoreProductReply;
import net.sk.china.common.model.user.User;
import net.sk.china.common.utils.DateUtil;
import net.sk.china.common.utils.RedisUtil;
import net.sk.china.common.vo.StoreOrderInfoOldVo;
import net.sk.china.platform.constants.Constants;
import net.sk.china.platform.constants.IntegralRecordConstants;
import net.sk.china.platform.model.user.UserIntegralRecord;
import net.sk.china.platform.service.order.OrderTaskService;
import net.sk.china.platform.service.order.StoreOrderInfoService;
import net.sk.china.platform.service.order.StoreOrderService;
import net.sk.china.platform.service.order.StoreOrderStatusService;
import net.sk.china.platform.service.product.StoreProductAttrValueService;
import net.sk.china.platform.service.product.StoreProductReplyService;
import net.sk.china.platform.service.product.StoreProductService;
import net.sk.china.platform.service.system.SystemConfigService;
import net.sk.china.platform.service.user.UserIntegralRecordService;
import net.sk.china.platform.service.user.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * OrderTaskServiceImpl 接口实现
 * +----------------------------------------------------------------------
 * | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * +----------------------------------------------------------------------
 * | Copyright (c) 2018-2024 聊来All rights reserved.
 * +----------------------------------------------------------------------
 * | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * +----------------------------------------------------------------------
 * | @Author: 聊来 <18970881148@qq.com>
 * +----------------------------------------------------------------------
 * | DateTime: 2024/6/14 21:26
 * +----------------------------------------------------------------------
 */

@Service
public class OrderTaskServiceImpl implements OrderTaskService {

    private static final Logger logger = LoggerFactory.getLogger(OrderTaskServiceImpl.class);

    private final RedisUtil redisUtil;

    private final StoreOrderService storeOrderService;

    private final UserService userService;

    private final UserIntegralRecordService userIntegralRecordService;

    private final TransactionTemplate transactionTemplate;

    private final StoreOrderStatusService storeOrderStatusService;

    private final StoreOrderInfoService storeOrderInfoService;

    private final StoreProductService storeProductService;

    private final StoreProductAttrValueService storeProductAttrValueService;

    private final StoreProductReplyService storeProductReplyService;

    private final SystemConfigService systemConfigService;

    public OrderTaskServiceImpl(RedisUtil redisUtil, StoreOrderService storeOrderService, UserService userService, UserIntegralRecordService userIntegralRecordService,
                                TransactionTemplate transactionTemplate, StoreOrderStatusService storeOrderStatusService, StoreOrderInfoService storeOrderInfoService,
                                StoreProductService storeProductService, StoreProductAttrValueService storeProductAttrValueService, StoreProductReplyService storeProductReplyService,
                                SystemConfigService systemConfigService) {
        this.redisUtil = redisUtil;
        this.storeOrderService = storeOrderService;
        this.userService = userService;
        this.userIntegralRecordService = userIntegralRecordService;
        this.transactionTemplate = transactionTemplate;
        this.storeOrderStatusService = storeOrderStatusService;
        this.storeOrderInfoService = storeOrderInfoService;
        this.storeProductService = storeProductService;
        this.storeProductAttrValueService = storeProductAttrValueService;
        this.storeProductReplyService = storeProductReplyService;
        this.systemConfigService = systemConfigService;
    }

    /**
     * 执行用户退款申请
     */
    @Override
    public void refundApply() {
        String redisKey = Constants.ORDER_TASK_REDIS_KEY_AFTER_REFUND_BY_USER;
        Long size = redisUtil.getListSize(redisKey);
        if (size < 1) {
            return;
        }
        for (int i = 0; i < size; i++) {
            //如果10秒钟拿不到一个数据，那么退出循环
            Object orderId = redisUtil.getRightPop(redisKey, 10L);
            if (null == orderId) {
                continue;
            }
            try {
                StoreOrder storeOrder = storeOrderService.getById(Integer.valueOf(orderId.toString()));
                if (ObjectUtil.isNull(storeOrder)) {
                    throw new TalkException("订单不存在,orderNo = " + orderId);
                }
                boolean result = refundOrder(storeOrder);
                if (!result) {
                    logger.error("订单退款错误：result = " + result);
                    redisUtil.lPush(redisKey, orderId);
                }
            } catch (Exception e) {
                logger.error("订单退款错误：" + e.getMessage());
                redisUtil.lPush(redisKey, orderId);
            }
        }
    }

    /**
     * 订单收货
     */
    @Override
    public void orderReceiving() {
        String redisKey = Constants.ORDER_TASK_REDIS_KEY_AFTER_TAKE_BY_USER;
        Long size = redisUtil.getListSize(redisKey);
        if (size < 1) {
            return;
        }
        for (int i = 0; i < size; i++) {
            //如果10秒钟拿不到一个数据，那么退出循环
            Object id = redisUtil.getRightPop(redisKey, 10L);
            if (null == id) {
                continue;
            }
            try {
                boolean result = orderReceiving(Integer.valueOf(id.toString()));
                if (!result) {
                    redisUtil.lPush(redisKey, id);
                }
            } catch (Exception e) {
                redisUtil.lPush(redisKey, id);
            }
        }
    }


    /**
     * 完成订单
     */
    @Override
    public void complete() {
        String redisKey = Constants.ORDER_TASK_REDIS_KEY_AFTER_COMPLETE_BY_USER;
        Long size = redisUtil.getListSize(redisKey);
        if (size < 1) {
            return;
        }
        for (int i = 0; i < size; i++) {
            //如果10秒钟拿不到一个数据，那么退出循环
            Object data = redisUtil.getRightPop(redisKey, 10L);
            if (null == data) {
                continue;
            }
            try {
                StoreOrder storeOrder = JSONObject.toJavaObject(JSONObject.parseObject(data.toString()), StoreOrder.class);
                boolean result = storeOrderStatusService.createLog(storeOrder.getId(), "check_order_over", "用户评价");
                if (!result) {
                    redisUtil.lPush(redisKey, data);
                }
            } catch (Exception e) {
                redisUtil.lPush(redisKey, data);
            }
        }
    }

    /**
     * 用户取消订单
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, TalkException.class})
    public void cancelByUser() {
        String redisKey = Constants.ORDER_TASK_REDIS_KEY_AFTER_CANCEL_BY_USER;
        Long size = redisUtil.getListSize(redisKey);
        if (size < 1) {
            return;
        }
        for (int i = 0; i < size; i++) {
            //如果10秒钟拿不到一个数据，那么退出循环
            Object data = redisUtil.getRightPop(redisKey, 10L);
            if (null == data) {
                continue;
            }
            try {
                StoreOrder storeOrder = storeOrderService.getById(Integer.valueOf(data.toString()));
                boolean result = cancelByUser(storeOrder);
                if (!result) {
                    redisUtil.lPush(redisKey, data);
                }
            } catch (Exception e) {
                redisUtil.lPush(redisKey, data);
            }
        }
    }

    /**
     * 订单自动完成
     */
    @Override
    public void autoComplete() {
        // 查找所有收获状态订单
        List<StoreOrder> orderList = storeOrderService.findIdAndUidListByReceipt();
        if (CollUtil.isEmpty(orderList)) {
            return;
        }

        // 根据订单状态表判断订单是否可以自动完成
        for (StoreOrder order : orderList) {
            StoreOrderStatus orderStatus = storeOrderStatusService.getLastByOrderId(order.getId());
            if (!orderStatus.getChangeType().equals("user_take_delivery")) {
                logger.error("订单自动完成：订单记录最后一条不是收货状态，orderId = " + order.getId());
                continue;
            }
            // 判断是否到自动完成时间（收货时间向后偏移7天）
            LocalDateTime comTime = orderStatus.getCreateTime().plusDays(7);
            if (comTime.isBefore(DateUtil.getNowTime())) {
                continue;
            }

            /**
             * ---------------
             * 自动好评转完成
             * ---------------
             */
            // 获取订单详情
            List<StoreOrderInfoOldVo> orderInfoVoList = storeOrderInfoService.getOrderListByOrderId(order.getId());
            if (CollUtil.isEmpty(orderInfoVoList)) {
                logger.error("订单自动完成：无订单详情数据，orderId = " + order.getId());
                continue;
            }
            List<StoreProductReply> replyList = CollUtil.newArrayList();
            User user = userService.getById(order.getUid());
            // 生成评论
            for (StoreOrderInfoOldVo orderInfo : orderInfoVoList) {
                // 判断是否已评论
                if (orderInfo.getInfo().getIsReply().equals(1)) {
                    continue;
                }
                String replyType = "product";
                StoreProductReply reply = new StoreProductReply();
                reply.setUid(order.getUid());
                reply.setOid(order.getId());
                reply.setProductId(orderInfo.getProductId());
                reply.setUnique(orderInfo.getUnique());
                reply.setReplyType(replyType);
                reply.setProductScore(5);
                reply.setServiceScore(5);
                reply.setComment("");
                reply.setPics("");
                reply.setNickname(user.getNickname());
                reply.setAvatar(user.getAvatar());
                reply.setSku(orderInfo.getInfo().getSku());
                reply.setCreateTime(DateUtil.getNowTime());
                replyList.add(reply);
            }
            order.setStatus(Constants.NUM_THREE);
            Boolean execute = transactionTemplate.execute(e -> {
                storeOrderService.updateById(order);
                storeProductReplyService.saveBatch(replyList);
                return Boolean.TRUE;
            });
            if (Boolean.TRUE.equals(execute)) {
                redisUtil.lPush(Constants.ORDER_TASK_REDIS_KEY_AFTER_COMPLETE_BY_USER, order.getId());
            } else {
                logger.error("订单自动完成：更新数据库失败，orderId = " + order.getId());
            }
        }
    }

    /**
     * 自动取消未支付订单
     */
    @Override
    public void autoCancel() {
        String redisKey = "order_auto_cancel_key";
        Long size = redisUtil.getListSize(redisKey);
        if (size < 1) {
            return;
        }
        for (int i = 0; i < size; i++) {
            //如果10秒钟拿不到一个数据，那么退出循环
            Object data = redisUtil.getRightPop(redisKey, 10L);
            if (null == data) {
                continue;
            }
            try {
                StoreOrder storeOrder = storeOrderService.getByOderId(String.valueOf(data));
                if (ObjectUtil.isNull(storeOrder)) {
                    throw new TalkException("订单不存在，orderNo: " + data);
                }
                boolean result = autoCancel(storeOrder);
                if (!result) {
                    redisUtil.lPush(redisKey, data);
                }
            } catch (Exception e) {
                e.printStackTrace();
                redisUtil.lPush(redisKey, data);
            }
        }
    }

    /**
     * 订单退款处理
     * 1、写订单日志 2、回滚消耗积分 3、回滚获得积分 4、回滚库存
     * @return {@code boolean}
     */
    public boolean refundOrder(StoreOrder storeOrder) {
        // 获取用户对象
        User user = userService.getById(storeOrder.getUid());
        if (ObjectUtil.isNull(user)) {
            logger.error("订单退款处理，对应的用户不存在,storeOrder===>" + storeOrder);
            return Boolean.FALSE;
        }
        LocalDateTime dateTime = DateUtil.getNowTime();
        // 回滚积分
        List<UserIntegralRecord> integralRecordList = userIntegralRecordService.findListByOrderIdAndUid(storeOrder.getOrderId(), storeOrder.getUid());
        integralRecordList.forEach(record -> {
            if (record.getType().equals(IntegralRecordConstants.INTEGRAL_RECORD_TYPE_SUB)) {// 订单抵扣部分
                user.setIntegral(user.getIntegral() + record.getIntegral());
                record.setId(null);
                record.setTitle(IntegralRecordConstants.BROKERAGE_RECORD_TITLE_REFUND);
                record.setType(IntegralRecordConstants.INTEGRAL_RECORD_TYPE_ADD);
                record.setBalance(user.getIntegral());
                record.setMark(StrUtil.format("订单退款，返还支付扣除得{}积分", record.getIntegral()));
                record.setStatus(IntegralRecordConstants.INTEGRAL_RECORD_STATUS_COMPLETE);
                record.setUpdateTime(dateTime);
            } else if (record.getType().equals(IntegralRecordConstants.INTEGRAL_RECORD_TYPE_ADD)) {// 冻结积分部分
                record.setStatus(IntegralRecordConstants.INTEGRAL_RECORD_STATUS_INVALIDATION);
                record.setUpdateTime(dateTime);
            }
        });
        List<UserIntegralRecord> addIntegralList = integralRecordList.stream().filter(e -> ObjectUtil.isNull(e.getId())).collect(Collectors.toList());
        List<UserIntegralRecord> updateIntegralList = integralRecordList.stream().filter(e -> ObjectUtil.isNotNull(e.getId())).collect(Collectors.toList());

        StoreOrder tempOrder = new StoreOrder();
        tempOrder.setId(storeOrder.getId());
        tempOrder.setRefundStatus(2);

        Boolean execute = transactionTemplate.execute(e -> {
            //写订单日志
            storeOrderStatusService.saveRefund(storeOrder.getId(), storeOrder.getRefundPrice(), "成功");

            // 更新用户数据
            userService.updateById(user);

            // 积分部分
            if (CollUtil.isNotEmpty(addIntegralList)) {
                userIntegralRecordService.saveBatch(addIntegralList);
            }
            if (CollUtil.isNotEmpty(updateIntegralList)) {
                userIntegralRecordService.updateBatchById(updateIntegralList);
            }

            // 回滚库存
            rollbackStock(storeOrder);

            storeOrderService.updateById(tempOrder);

            return Boolean.TRUE;
        });

        if (Boolean.FALSE.equals(execute)) { logger.error("订单退款处理失败"); }

        return true;
    }

    /**
     * 订单收货task处理
     * @param orderId 订单id
     * @return {@code boolean}
     */
    public boolean orderReceiving(Integer orderId) {
        StoreOrder storeOrder = storeOrderService.getById(orderId);
        if (ObjectUtil.isNull(storeOrder)) {
            throw new TalkException(StrUtil.format("订单收货task处理，未找到订单，id={}", orderId));
        }
        User user = userService.getById(storeOrder.getUid());

        // 获取积分记录
        List<UserIntegralRecord> integralRecordList = userIntegralRecordService.findListByOrderIdAndUid(storeOrder.getOrderId(), storeOrder.getUid());
        List<UserIntegralRecord> userIntegralRecordList = integralRecordList.stream().filter(e -> e.getType().equals(IntegralRecordConstants.INTEGRAL_RECORD_TYPE_ADD)).collect(Collectors.toList());
        for (UserIntegralRecord record : userIntegralRecordList) {
            if (!record.getStatus().equals(IntegralRecordConstants.INTEGRAL_RECORD_STATUS_CREATE)) {
                throw new TalkException(StrUtil.format("订单收货task处理，订单积分记录不是创建状态，id={}", orderId));
            }
            // 佣金进入冻结期
            record.setStatus(IntegralRecordConstants.INTEGRAL_RECORD_STATUS_FROZEN);
            // 计算解冻时间
            Long thawTime = cn.hutool.core.date.DateUtil.current(false);
            if (record.getFrozenTime() > 0) {
                DateTime dateTime = cn.hutool.core.date.DateUtil.offsetDay(new Date(), record.getFrozenTime());
                thawTime = dateTime.getTime();
            }
            record.setThawTime(thawTime);
        }

        Boolean execute = transactionTemplate.execute(e -> {
            // 日志
            storeOrderStatusService.createLog(storeOrder.getId(), "user_take_delivery", Constants.ORDER_STATUS_STR_TAKE);
            // 积分进入冻结期
            if (CollUtil.isNotEmpty(userIntegralRecordList)) {
                userIntegralRecordService.updateBatchById(userIntegralRecordList);
            }
            return Boolean.TRUE;
        });

        if (Boolean.FALSE.equals(execute)) { logger.error("订单收货task处理失败"); }

        return true;
    }

    /**
     * 用户取消订单 1、修改订单状态 （用户操作的时候已处理）2、写订单日志 3、回滚库存 5、回滚积分
     * @param storeOrder 订单信息
     * @return {@code boolean}
     */
    public boolean cancelByUser(StoreOrder storeOrder) {
        try{
            //写订单日志
            storeOrderStatusService.createLog(storeOrder.getId(), "cancel_order", "取消订单");
            return rollbackStock(storeOrder);
        }catch (Exception e){
            return false;
        }
    }

    /**
     * 回滚库存
     * @param storeOrder 订单信息
     * @return {@code boolean}
     */
    public boolean rollbackStock(StoreOrder storeOrder) {
        try{
            // 查找出商品详情
            List<StoreOrderInfo> orderInfoList = storeOrderInfoService.getListByOrderNo(storeOrder.getOrderId());
            if(null == orderInfoList || orderInfoList.size() < 1){
                return true;
            }

            for (StoreOrderInfo orderInfoVo : orderInfoList) {
                storeProductService.operationStock(orderInfoVo.getProductId(), orderInfoVo.getPayNum(), "add");
                storeProductAttrValueService.operationStock(orderInfoVo.getAttrValueId(), orderInfoVo.getPayNum(), "add", Constants.PRODUCT_TYPE_NORMAL);
            }
        }catch (Exception e){
            logger.error("回滚库存失败，error = " + e.getMessage());
            return true;
        }
        return true;
    }

    /**
     * 超时未支付系统自动取消
     * @param storeOrder 订单信息
     * @return {@code boolean}
     */
    public boolean autoCancel(StoreOrder storeOrder) {
        // 判断订单是否支付
        if (storeOrder.getPaid()) {
            return Boolean.TRUE;
        }
        if (storeOrder.getIsDel() || storeOrder.getIsSystemDel()) {
            return Boolean.TRUE;
        }
        // 获取过期时间
        String cancelStr;
        DateTime cancelTime;
        if (storeOrder.getType().equals(1)) {
            cancelStr = "3";
            cancelTime = cn.hutool.core.date.DateUtil.offset(Date.from(storeOrder.getCreateTime().atZone(DateUtil.DEFAULT_ZONE_ID).toInstant()), DateField.MINUTE, Integer.parseInt(cancelStr));
        } else {
            cancelStr = systemConfigService.getValueByKey("order_cancel_time");
            if (StrUtil.isBlank(cancelStr)) {
                cancelStr = "1";
            }
            cancelTime = cn.hutool.core.date.DateUtil.offset(Date.from(storeOrder.getCreateTime().atZone(DateUtil.DEFAULT_ZONE_ID).toInstant()), DateField.HOUR_OF_DAY, Integer.parseInt(cancelStr));
        }
        long between = cn.hutool.core.date.DateUtil.between(cancelTime, cn.hutool.core.date.DateUtil.date(), DateUnit.SECOND, false);
        if (between < 0) {// 未到过期时间继续循环
            return Boolean.FALSE;
        }
        storeOrder.setIsDel(true);
        storeOrder.setIsSystemDel(true);
        Boolean execute = transactionTemplate.execute(e -> {
            storeOrderService.updateById(storeOrder);
            storeOrderStatusService.createLog(storeOrder.getId(), "cancel", "到期未支付系统自动取消");
            return Boolean.TRUE;
        });
        // 回滚库存
        if (Boolean.TRUE.equals(execute)) { rollbackStock(storeOrder); }

        return true;
    }
}
